home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / t3_1 / doc.lha / documentation / manual / stream.mss < prev    next >
Text File  |  1987-06-30  |  19KB  |  507 lines

  1. @part[Streams, Root "TMAN.MSS"] @Comment{-*-System:TMAN-*-}
  2. @chap[Streams]
  3.  
  4. @dc[ Some general comments are in order: ]
  5.  
  6. A @i[stream] is any object which handles stream operations.  In general,
  7. streams are objects which contain pointers into sequences of objects.
  8. The stream operations provide for obtaining objects from such a
  9. sequence, advancing a stream's pointer, performing side effects
  10. on the sequence itself, and so forth.
  11.  
  12. @dc[ Opening and closing streams. ]
  13.  
  14. @dc[ Input and output streams. ]
  15.  
  16. @dc[ Comparison with streams in the AI sense - those don't have state; they
  17. are instead like infinite (lazy) lists. ]
  18.  
  19. @tau[] programs communicate with the external world via @ix[streams].
  20. Streams may access file systems or terminals.  They may also be used
  21. to implement filters and buffers of various sorts.
  22.  
  23. Streams are manipulated using generic operations.  Most of the
  24. procedures described below are generic operations, and their
  25. descriptions either specify the behavior of their default methods
  26. or of the methods for system-supplied streams.  Users may create
  27. streams to their own specifications using @tc[OBJECT]-expressions.
  28. As long as a user stream supports
  29. @tc[READ-CHAR] and @tc[UNREAD-CHAR] (for input streams) or
  30. @tc[WRITE-CHAR] (for output streams), most of the other I/O operations
  31. will work with them.
  32.  
  33.  
  34. @section[General]
  35.  
  36. @info[NOTES="Type predicate operation"]
  37. @desc[(STREAM? @i[object]) @yl[] @i[boolean]]
  38. Returns true if @i[object] is a stream.
  39. @EndDesc[STREAM?]
  40.  
  41. @info[NOTES="Type predicate operation"]
  42. @desc[(INPUT-STREAM? @i[object]) @yl[] @i[boolean]]
  43. Returns true if @i[object] is an input stream.
  44. @EndDesc[INPUT-STREAM?]
  45.  
  46. @info[NOTES="Type predicate operation"]
  47. @desc[(OUTPUT-STREAM? @i[object]) @yl[] @i[boolean]]
  48. Returns true if @i[object] is an output stream.
  49. @EndDesc[OUTPUT-STREAM?]
  50.  
  51. @info[NOTES="Type predicate operation"]
  52. @desc[(INTERACTIVE-STREAM? @i[object]) @yl[] @i[boolean]]
  53. Returns true if @i[object] is an @iix[interactive] stream.
  54. An interactive stream is any input stream which is likely to have
  55. a human being at the other end, for example, a terminal input stream.
  56. @EndDesc[INTERACTIVE-STREAM?]
  57.  
  58. @info[NOTES="Type predicate"]
  59. @desc[(EOF? @i[object]) @yl[] @i[boolean]]
  60. Returns true if @i[object] is the end-of-file token.
  61. (@qu"End-of-stream" would be a more appropriate term.)
  62. @EndDesc[EOF?]
  63.  
  64. @desc[*EOF* @yl[] @i[end-of-file]]
  65. This global variable holds the end-of-file token.
  66. @EndDesc[*EOF*]
  67.  
  68. @info[Notes "Special form"]
  69. @desc[@el[](WITH-OPEN-STREAMS @i[specs] . @i[body]) @yl[] @i[object]]
  70. @tc[WITH-OPEN-STREAMS] has the same syntax as @tc[LET],
  71. and similar semantics.
  72. Each @i[spec] should be of the form @wt[(@i[variable stream])].
  73. Each @i[stream] expression
  74. is evaluated, and should evaluate to a stream;
  75. for example, @i[stream] would typically be an expression
  76. involving @tc[OPEN] or @tc[MAYBE-OPEN].
  77. The @i[body], an implicit block, is evaluated in a lexical context in which
  78. each @i[variable] is bound to the value of the corresponding
  79. @i[stream] expression.
  80. The streams are closed,
  81. and the value of @i[body] is returned.
  82.  
  83. @tc[WITH-OPEN-STREAMS] is the preferred way to use stream creation
  84. operations such as @tc[OPEN].  It ensures that the
  85. streams will be closed, even if there is a non-local exit (a
  86. @tc[(RESET)] or any other kind of
  87. throw) out of @i[body] or any of the @i[stream] expressions.
  88. (See @tc[UNWIND-PROTECT], page @pageref[UNWIND-PROTECT].)
  89.  
  90. For an example, see @tc[OPEN], page @pageref[OPEN].
  91. @EndDesc[WITH-OPEN-STREAMS]
  92.  
  93. @info[NOTES="Operation"]
  94. @desc[(CLOSE @i[stream]) @yl[] @i[undefined]]
  95. Closes @i[stream]; indicates that no more input or output is intended,
  96. and that any resources associated with it may be freed.
  97. @EndDesc[CLOSE]
  98.  
  99. @desc[(STRING->INPUT-STREAM @i[string]) @yl[] @i[stream]]
  100. Returns an input stream which yields successive characters of @i[string]
  101. on successive @tc[READ-CHAR]'s.
  102. @EndDesc[STRING->INPUT-STREAM]
  103.  
  104. @info[notes "Special form"]
  105. @desc[(WITH-INPUT-FROM-STRING (@i[variable string]) . @i[body]) @yl[] @~
  106. @i[value-of-body]]
  107. Opens an input stream to @i[string], binds @i[variable] to that
  108. stream, and evaluates @i[body], returning whatever @i[body] returns.
  109. @ProgramExample[
  110. (WITH-INPUT-FROM-STRING (@i[variable string]) . @i[body])
  111.   @ce[]
  112. (WITH-OPEN-STREAMS ((@i[variable] (STRING->INPUT-STREAM @i[string])))
  113.   . @i[body])
  114. ]
  115. @EndDesc[WITH-INPUT-FROM-STRING]
  116.  
  117. @info[NOTES="Special form"]
  118. @desc[(WITH-OUTPUT-TO-STRING @i[var . body]) @yl[] @i[string]]
  119. Binds @i[var] to an output stream.  The @i[body] (an implicit block) is
  120. evaluated, and any characters written to the stream are
  121. collected in a string, which is returned as the value of the
  122. @tc[WITH-OUTPUT-TO-STRING] form.
  123. @begin[ProgramExample]
  124. (WITH-OUTPUT-TO-STRING FOO (WRITE FOO '(A B)))  @ev[]  "(A B)"
  125. @end[ProgramExample]
  126. @EndDesc[WITH-OUTPUT-TO-STRING]
  127.  
  128.  
  129. @section[Stream switches]
  130.  
  131. @info[Notes "Settable"]
  132. @desc[(TERMINAL-INPUT) @yl[] @i[stream]]
  133. Accesses the default stream for input from the terminal.
  134.  
  135. Note that an end-of-file condition on the terminal input stream (see
  136. page @pageref[end-of-file]) will cause the end-of-file token to be
  137. returned as the value of the next input operation on that stream,
  138. but will not cause the stream to become closed.  This is an exception
  139. to the normal rule that no input is available from a stream following
  140. an end-of-file condition on it.
  141. @EndDesc[TERMINAL-INPUT]
  142.  
  143. @info[Notes "Settable"]
  144. @desc[(TERMINAL-OUTPUT) @yl[] @i[stream]]
  145. Accesses the default stream for output to the terminal.
  146. @EndDesc[TERMINAL-OUTPUT]
  147.  
  148. @info[Notes "Settable"]
  149. @desc[@el[](STANDARD-INPUT) @yl[] @i[stream]]
  150. Accesses the default standard input stream.
  151. Initially, this is the same as the value of @tc[(TERMINAL-INPUT)].
  152.  
  153. The intent is that a program could do all its input from
  154. the standard input stream.
  155. By default, input would come from the terminal.  But some procedure could
  156. set the standard input stream to be a file, for example, and then
  157. call the program, which would automatically read from the file.
  158. This same idea is used for all the following predefined streams.
  159. @EndDesc[STANDARD-INPUT]
  160.  
  161. @info[Notes "Settable"]
  162. @desc[@el[](STANDARD-OUTPUT) @yl[] @i[stream]]
  163. Accesses the default standard output stream.
  164. Initially, this is the same as the value of @tc[(TERMINAL-OUTPUT)].
  165. @EndDesc[STANDARD-OUTPUT]
  166.  
  167. @info[Notes "Settable"]
  168. @desc[(ERROR-OUTPUT) @yl[] @i[stream]]
  169. Initially, yields the same value as @tc[(TERMINAL-OUTPUT)].
  170. @EndDesc[ERROR-OUTPUT]
  171.  
  172. @info[Notes "Settable"]
  173. @desc[(DEBUG-OUTPUT) @yl[] @i[stream]]
  174. Initially, yields the same value as @tc[(TERMINAL-OUTPUT)].
  175. @EndDesc[DEBUG-OUTPUT]
  176.  
  177.  
  178. @section[Input]
  179.  
  180. @AnEquivE[Tfn="READ-CHAR",Efn="TYI"]
  181. @AnEquivE[Tfn="READ-CHAR",Efn="READCH"]
  182. @info[NOTES="Operation"]
  183. @descN[
  184.   F1="@el[](READ-CHAR @i[stream]) @yl[] @i[character] @r[or] @i[end-of-file]",
  185.   FN1="READ-CHAR",
  186.   F2="@el[](READC @i[stream]) @yl[] @i[character] @r[or] @i[end-of-file]",
  187.   FN2="READC"
  188. ]
  189. Reads a single character from @i[stream], advances the stream pointer,
  190. and returns the character read.  If no character is available, then
  191. the end-of-file token is returned.
  192. @EndDescN[]
  193.  
  194. @info[NOTES="Operation"]
  195. @descN[
  196.   F1 = "(UNREAD-CHAR @i[stream]) @yl[] @i[undefined]",
  197.   FN1 = "UNREAD-CHAR",
  198.   F2 = "(UNREADC @i[stream]) @yl[] @i[undefined]",
  199.   FN2 = "UNREADC"
  200. ]
  201. Backs up @i[stream]'s pointer into its corresponding sequence of
  202. characters by one character.  This causes the
  203. next @tc[READ-CHAR] from @i[stream] to return @i[character] instead of
  204. actually reading another character.  @i[Character] is returned.
  205. @tc[UNREAD-CHAR] is convenient for implementing one-character-lookahead
  206. scanners.  Only the previous character @tc[READ-CHAR]'ed from @i[stream]
  207. may be put back, and it may be put back only once.
  208. @dc{ Explain why one needs to supply the character at all. }
  209. @EndDescN[]
  210.  
  211. @AnEquivE[Tfn="PEEK-CHAR",Efn="TYIPEEK"]
  212. @info[NOTES="Operation"]
  213. @descN[
  214.   F1="(PEEK-CHAR @i[stream]) @yl[] @i[character] @r[or] @i[end-of-file]",
  215.   FN1="PEEK-CHAR",
  216.   F2="(PEEKC @i[stream]) @yl[] @i[character] @r[or] @i[end-of-file]",
  217.   FN2="PEEKC"
  218. ]
  219. Returns the next character available on @i[stream] without
  220. advancing the stream's pointer.
  221. If no character is there then the end-of-file token is returned.
  222.   @begin[ProgramExample]
  223. (PEEK-CHAR @i[stream])  @ce[]  
  224.   (BLOCK0 (READ-CHAR @i[stream]) (UNREAD-CHAR @i[stream]))
  225.   @end[ProgramExample]
  226. @EndDescN[]
  227.  
  228. @AnEquivE[Tfn="READ-LINE",Efn="READLINE"]
  229. @info[NOTES="Operation"]
  230. @desc[(READ-LINE @i[stream]) @yl[] @i[string] @r[or] @i[end-of-file]]
  231. Reads a line of input from @i[stream] and returns it as a string.
  232. If no input is available then the end-of-file token is returned.
  233. @EndDesc[READ-LINE]
  234.  
  235. @AnEquivE[Tfn="READ",Efn="READ"]
  236. @info[NOTES="Operation"]
  237. @desc[@el[](READ @i[stream]) @yl[] @i[object] @r[or] @i[end-of-file]]
  238. Reads an object from @i[stream].  The default method simply calls
  239. @tc[READ-OBJECT], passing it the stream and
  240. the stream's current associated read table.  See @tc[READ-OBJECT],
  241. page @pageref[READ-OBJECT], and @tc[STREAM-READ-TABLE], page
  242. @pageref[STREAM-READ-TABLE].
  243. @EndDesc[READ]
  244.  
  245. @desc[(READ-REFUSING-EOF @i[stream]) @yl[] @i[object]]
  246. This is like @tc[READ] but should be used in cases where an end-of-file
  247. is not appropriate or is not handled, such as within
  248. the definition of a read macro.
  249. @EndDesc[READ-REFUSING-EOF]
  250.  
  251. @desc[(READ-OBJECTS-FROM-STRING @i[string]) @yl[] @i[list]]
  252. Returns a list of all the objects that could be read from the string.
  253. @begin[ProgramExample]
  254. (READ-OBJECTS-FROM-STRING "A B C")           @ev[]  (A B C)
  255. (READ-OBJECTS-FROM-STRING " 015  ( Foo ) ")  @ev[]  (15 (FOO))
  256. (READ-OBJECTS-FROM-STRING "")                @ev[]  ()
  257. @end[ProgramExample]
  258. @EndDesc[READ-OBJECTS-FROM-STRING]
  259.  
  260. @info[NOTES="Operation"]
  261. @desc[(CLEAR-INPUT @i[stream]) @yl[] @i[undefined]]
  262. Discards any buffered input for @i[stream].
  263. The precise action of this operation is implementation-dependent.
  264. @EndDesc[CLEAR-INPUT]
  265.  
  266.  
  267. @section[Output]
  268.  
  269. @info[EQUIV="PRIN1",NOTES="Operation"]
  270. @desc[@el[](PRINT @i[object stream]) @yl[] @i[undefined]]
  271. Prints @i[object] on @i[stream] according to the current read-table.
  272. This is an operation, so objects may decide how they would like
  273. to print.
  274. @EndDesc[PRINT]
  275.  
  276. @AnEquivE[Tfn="WRITE",Efn="PRIN1"]
  277. @info[NOTES="Operation"]
  278. @desc[(WRITE @i[stream object]) @yl[] @i[undefined]]
  279. Prints the @i[object] on @i[stream].  This is like @tc[PRINT] with the
  280. argument order reversed.
  281. This is an operation, so particular streams may decide how they want
  282. to write objects to themselves.
  283. @EndDesc[WRITE]
  284.  
  285. @AnEquivE[Tfn="WRITEC",Efn="TYO"]
  286. @info[NOTES="Operation"]
  287. @descN[
  288. F1="@el[](WRITE-CHAR @i[stream character]) @yl[] @i[undefined]",
  289.      FN1="WRITE-CHAR",
  290. F2="@el[](WRITEC @i[stream character]) @yl[] @i[undefined]",
  291.      FN2="WRITEC"
  292. ]
  293. Writes a single @i[character] to @i[stream].
  294. @EndDescN[]
  295.  
  296. @AnEquivE[Tfn="WRITES",Efn="PRINC"]
  297. @info[NOTES="Operation"]
  298. @descN[
  299. F1="@el[](WRITE-STRING @i[stream string]) @yl[] @i[undefined]",
  300.      FN1="WRITE-STRING",
  301. F2="@el[](WRITES @i[stream string]) @yl[] @i[undefined]",
  302.      FN2="WRITES"
  303. ]
  304. Writes @i[string] to @i[stream].
  305. @EndDescN[]
  306.  
  307. @info[NOTES="Operation"]
  308. @desc[(WRITE-LINE @i[stream string]) @yl[] @i[undefined]]
  309. Writes @i[string] to @i[stream] (like @tc[WRITE-STRING]),
  310. then does a @tc[NEWLINE] operation.
  311. @EndDesc[WRITE-LINE]
  312.  
  313. @desc[(WRITE-SPACES @i[stream count]) @yl[] @i[undefined]]
  314. Writes @i[count] space characters to @i[stream].
  315. @EndDesc[WRITE-SPACES]
  316.  
  317. @info[EQUIV="PRINC",NOTES="Operation"]
  318. @desc[(DISPLAY @i[object stream]) @yl[] @i[undefined]]
  319. Prints @i[object] on @i[stream], but omits any slashes, delimiters, etc., when
  320. printing strings, symbols, and characters.
  321. @EndDesc[DISPLAY]
  322.  
  323. @info[EQUIV="SPRINTER",NOTES="Operation"]
  324. @desc[(PRETTY-PRINT @i[object stream]) @yl[] @i[undefined]]
  325. Pretty-prints @i[object] on @i[stream].
  326. @EndDesc[PRETTY-PRINT]
  327.  
  328. @info[NOTES="Operation",EQUIV="TERPRI"]
  329. @desc[(NEWLINE @i[stream]) @yl[] @i[undefined]]
  330. Begins a new line on the given output @i[stream].
  331. @EndDesc[NEWLINE]
  332.  
  333. @info[NOTES="Operation",EQUIV="TERPRI"]
  334. @desc[(FRESH-LINE @i[stream]) @yl[] @i[undefined]]
  335. If not at the beginning of a line,
  336. begins a new line on the given output @i[stream].
  337. @EndDesc[FRESH-LINE]
  338.  
  339. @info[NOTES="Operation"]
  340. @desc[(SPACE @i[stream]) @yl[] @i[undefined]]
  341. Write whitespace to @i[stream].  Ordinarily this will simply write
  342. a space character, but if the current output line has overflowed
  343. a @qu"reasonable" right margin, this will do a @tc[NEWLINE].
  344. @EndDesc[SPACE]
  345.  
  346. @info[NOTES="Operation"]
  347. @desc[(FORCE-OUTPUT @i[stream]) @yl[] @i[undefined]]
  348. Makes sure any buffered output to @i[stream] is forced out.
  349. This is useful especially with terminal output streams.
  350. The precise behavior of this operation is implementation-dependent.
  351. @EndDesc[FORCE-OUTPUT]
  352.  
  353.  
  354. @section[Formatted output]
  355.  
  356. @AnEquivE[Tfn="FORMAT",Efn="MSG"]
  357. @desc[@el[](FORMAT @i[destination control-string] . @i[rest]) @yl[] @i[string] @r[or] @i[undefined]]
  358. Performs formatted output.
  359. Characters in the @i[control-string] other than tilde (@tilde[])
  360. are simply written to @i[destination].
  361. When a tilde is encountered, special action is taken
  362. according to the character following the tilde.
  363.  
  364. @i[Destination] should be one of the following:
  365. @begin[Itemize]
  366.     A stream.  In this case, output is simply written to the stream.
  367.     The value returned by the call to @tc[FORMAT] is undefined.
  368.  
  369.     The standard true value.  (This is the value of the system variable @tc[T].)
  370.     This is equivalent to a stream argument of @tc[(STANDARD-OUTPUT)].
  371.     The value returned by the call to @tc[FORMAT] is undefined.
  372.  
  373.     Null.  In this case the output is collected in a string, as with
  374.     @tc[WITH-OUTPUT-TO-STRING].  This string is returned as the value of
  375.     the call to @tc[FORMAT].
  376. @end[Itemize]
  377.  
  378. The @tc[FORMAT] control sequences are as follows.
  379. (Case is irrelevant, so @tilde[]@tc[A] and @tilde[]@tc[a] behave identically.)
  380. @begin[Display]
  381.    @tilde[]@tc[A]  @tc[DISPLAY] the next format argument.
  382.    @tilde[]@tc[B]  Print the next argument in binary.
  383.    @tilde[]@tc[D]  Print the next argument in decimal (radix ten).
  384.    @tilde[]@tc[O]  Print the next argument in @ix[octal] (radix eight).
  385.    @tilde[]@tc[P]  Write the character @qu"@tc[s]" if the next argument,
  386.            which must be a number, is not equal to 1 (for plurals).
  387.    @tilde[]@tc[R]  @tilde[]@i[n]@tc[R] prints the next argument in radix @i[n].
  388.    @tilde[]@tc[S]  @tc[PRINT] the next format argument.
  389.    @tilde[]@tc[T]  @tilde[]@i[n]@tc[T] tabs to column @i[n] (@tc[HPOS]).
  390.    @tilde[]@tc[X]  Print the next argument in @ix[hexadecimal] (radix sixteen).
  391.    @tilde[]@tc[%]  Go to a new output line (@tc[NEWLINE]).
  392.    @tilde[]@tc[&]  Go to a fresh output line (@tc[FRESH-LINE]).
  393.    @tilde[]@tc[_]  Print a space, or go to a fresh output line (@tc[SPACE]).
  394.    @tilde[]@tilde[]  Write a tilde.
  395. @end[Display]
  396.  
  397. A tilde followed by any whitespace character is ignored, along with all
  398. following whitespace.
  399.  
  400. @begin[ProgramExample]
  401. (FORMAT NIL "The ~s eats grass." 'ELAND)  @ev[]  "The ELAND eats grass."
  402. (FORMAT NIL "The ~A eats grass." "kudu")  @ev[]  "The kudu eats grass."
  403. (FORMAT NIL "~S had ~X goat~P." '(SANDY SMITH) 31 31)
  404.   @ev[]  "(SANDY SMITH) had 1F goats."
  405. @end[ProgramExample]
  406.  
  407. @dc{ Explain numeric prefix parameters. }
  408.  
  409. @dc{ Are there other features? }
  410.  
  411. @dc{ Say somewhere that newlines follow output, like in C, rather than
  412. preceding output, as in Maclisp. }
  413. @EndDesc[FORMAT]
  414.  
  415.  
  416. @section[Miscellaneous]
  417.  
  418. @info[NOTES="Settable operation"]
  419. @desc[(STREAM-READ-TABLE @i[stream]) @yl[] @i[read-table]]
  420. Accesses the read table associated with @i[stream].
  421. See section @ref[readtables].
  422. @EndDesc[STREAM-READ-TABLE]
  423.  
  424. @info[NOTES="Settable operation"]
  425. @desc[(LINE-LENGTH @i[stream]) @yl[] @i[integer]]
  426. Returns the maximum width that lines read from @i[stream] are likely to take,
  427. or that lines written to @i[stream] ought to take.
  428.     @BeginInset[Bug:]
  429.     In @Timp[] 2.7, the @tc[LINE-LENGTH] of system-supplied streams is
  430.     not settable.
  431.     @EndInset[]
  432. @EndDesc[LINE-LENGTH]
  433.  
  434. @info[NOTES="Settable operation",EQUIV="CURSORPOS"]
  435. @desc[(HPOS @i[stream]) @yl[] @i[integer]]
  436. Accesses the current horizontal position (column number) of @i[stream].
  437. The leftmost position on a line is column 0.
  438. When assigned, as many spaces as necessary are written to bring the
  439. horizontal position to the assigned value.
  440. @EndDesc[HPOS]
  441.  
  442. @info[NOTES="Settable operation",EQUIV="CURSORPOS"]
  443. @desc[(VPOS @i[stream]) @yl[] @i[integer]]
  444. Accesses the current vertical position (line number) of @i[stream].
  445. The uppermost vertical position is line 0.
  446. @EndDesc[VPOS]
  447.  
  448. @info[notes "Special form"]
  449. @desc[(WITH-OUTPUT-WIDTH-STREAM @i[variable] . @i[body]) @yl[] @i[integer]]
  450. Binds @i[variable] to an output stream, and evaluates @i[body] in
  451. the augmented lexical environment.
  452. The characters sent to the output stream are not accumulated, but
  453. merely counted, and the total is returned as the value of
  454. @tc[WITH-OUTPUT-WIDTH-STREAM].
  455. @EndDesc[WITH-OUTPUT-WIDTH-STREAM]
  456.  
  457. @info[EQUIV="FLATSIZE"]
  458. @desc[(PRINTWIDTH @i[object]) @yl[] @i[integer]]
  459. Returns the number of @tc[WRITEC]'s
  460. which would be performed were @i[object] to be printed using @tc[PRINT].
  461. @ProgramExample[
  462. (PRINTWIDTH @i[object])
  463.   @ce[]
  464. (WITH-OUTPUT-WIDTH-STREAM STREAM (PRINT @i[object] STREAM))
  465. ]
  466. @EndDesc[PRINTWIDTH]
  467.  
  468. @info[EQUIV="FLATC"]
  469. @desc[(DISPLAYWIDTH @i[object]) @yl[] @i[integer]]
  470. Returns the number of @tc[WRITEC]'s
  471. which would be performed were @i[object] to be printed using @tc[DISPLAY].
  472. @PROGRAMEXAMPLE[
  473. (DISPLAYWIDTH @i[object])
  474.   @ce[]
  475. (WITH-OUTPUT-WIDTH-STREAM STREAM (DISPLAY @i[object] STREAM)
  476. ]
  477. @EndDesc[DISPLAYWIDTH]
  478.  
  479. @desc[(MAKE-BROADCAST-STREAM . @i[output-streams]) @yl[] @i[stream]]
  480. Returns a stream which will @qu"broadcast" all output operations to
  481. all of the @i[output-streams].  For example, if the stream @i[s] is the
  482. value of a call
  483.   @begin[ProgramExample]
  484. (MAKE-BROADCAST-STREAM @i[q] @i[r])
  485.   @end[ProgramExample]
  486. then any @tc[WRITEC] (@tc[WRITES], @tc[SPACE], etc.) operation
  487. to @i[s] will result in @tc[WRITEC] operations on both
  488. @i[q] and @i[r].
  489. @enddesc[MAKE-BROADCAST-STREAM]
  490.  
  491. @section[Example]
  492.  
  493. Here is an example of a user-defined stream.
  494. @tc[MAKE-PREFIXED-STREAM] returns a stream
  495. which prefixes each line written to a given stream with a given string.
  496. @begin[ProgramExample]
  497. (DEFINE (MAKE-PREFIXED-STREAM STREAM PREFIX)
  498.   (JOIN (OBJECT NIL
  499.                 ((NEWLINE SELF) (NEWLINE STREAM) (WRITES STREAM PREFIX))
  500.                 ((PRINT SELF OSTREAM)
  501.                  (FORMAT OSTREAM
  502.                          "#{Prefixed-stream@tilde[]_@tilde[]S@tilde[]_@tilde[]S}"
  503.                          STREAM
  504.                          PREFIX)))
  505.         STREAM))
  506. @end[ProgramExample]
  507.